/**
  * @file 		time.c
  * @brief		包含实现日期（年月日时分秒）转换以及读写相关功能文件。
  *
  * @copyright  Copyright (c) 2020~2030 ShenZhen Dxtc Technology Co., Ltd. 
  * All rights reserved.
  *
  * @version	v3.1
  * @author		FengLi
  * @date 		2021-08-02
  *
  * @note		鼎新同创·智能锁
  * 
  * @par 修改日志:
  * <1> 2021/08/02 v3.1 FengLi 创建初始版本
  *******************************************************************/
#include "osal.h"
#include "device.h"


#define ONE_SECOND (1ul)     ///< second
#define ONE_MINUTE (60ul)    ///< (60 * ONE_SECOND)
#define ONE_HOUR   (3600ul)  ///< (60 * ONE_MINUTE)
#define DAY_SEC    (86400ul) ///< (24*60*60)

/**
  * @brief   判断闰年
  * @details 详细说明：无
  * 
  * @param[in]  year：年份
  * 
  * @return 【1】：为闰年  【2】：非闰年
  */
static int32_t __isleap(int32_t year)
{
    return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}

/**
  * @brief   获取一年的天数
  * @details 详细说明：无
  * 
  * @param[in]  year：年份
  * 
  * @return 366 or 365
  */
static int __get_yeardays(int year)
{
    if (__isleap(year))
        return 366;
    return 365;
}

/**
  * @brief   时间戳转换成年月日时分秒
  * @details 详细说明：无
  * 
  * @param[in]  timestamp：以 1970.1.1 00:00:00 为起始时间的秒计数
  * @param[in]  pTime：年月日时分秒
  * 
  * @return NULL
  */
void OSAL_UTC2Time(uint32_t timestamp, uint8_t *pTime)
{
    uint32_t x;
    uint32_t i, mons[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    uint32_t utc = timestamp;
    uint16_t year;
    uint8_t month, day, hour, minute, second;

    for (i = 1970; utc > 0;)
    {
        x = __get_yeardays(i);
        if (utc >= x * DAY_SEC)
        {
            utc -= x * DAY_SEC;
            i++;
        }
        else
        {
            break;
        }
    }
    year = i;

    for (i = 0; utc > 0;)
    {
        if (__isleap(year))
            mons[1] = 29;

        if (utc >= mons[i] * DAY_SEC)
        {
            utc -= mons[i] * DAY_SEC;
            i++;
        }
        else
        {
            break;
        }
    }
    mons[1] = 28;
    month = i + 1;

    for (i = 1; utc > 0;)
    {
        if (utc >= DAY_SEC)
        {
            utc -= DAY_SEC;
            i++;
        }
        else
        {
            break;
        }
    }
    day = i;

    hour = utc / (60 * 60);
    minute = utc % (60 * 60) / 60;
    second = utc % 60;
    year = year % 100;

    pTime[0] = year;
    pTime[1] = month;
    pTime[2] = day;
    pTime[3] = hour;
    pTime[4] = minute;
    pTime[5] = second;
}

/**
  * @brief   年月日时分秒转换成时间戳
  * @details 详细说明：无
  * 
  * @param[in]  pTime：年月日时分秒
  * @param[in]  bcd：1 十进制 0 BCD
  * 
  * @return 返回时间戳（以 1970.1.1 00:00:00 为起始时间的秒计数）
  */
uint32_t OSAL_Time2UTC(uint8_t *pTime, uint8_t bcd)
{
    uint16_t i;
    uint16_t year;
    uint8_t month, day, hour, minute, second;
    const uint8_t mons[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    uint32_t utc = 0, temp;
    if (bcd)
    {
        year = OSAL_BCD2DEC(pTime[0]) + 2000;
        month = OSAL_BCD2DEC(pTime[1]);
        day = OSAL_BCD2DEC(pTime[2]);
        hour = OSAL_BCD2DEC(pTime[3]);
        minute = OSAL_BCD2DEC(pTime[4]);
        second = OSAL_BCD2DEC(pTime[5]);
    }
    else
    {
        year = pTime[0] + 2000;
        month = pTime[1];
        day = pTime[2];
        hour = pTime[3];
        minute = pTime[4];
        second = pTime[5];
    }
    for (i = 1970; i < year; i++)
    {
        utc += __get_yeardays(i);
    }
    for (i = 0; i < month - 1; i++)
    {
        utc += mons[i];
    }
    if (__isleap(year) && month > 2)
    {
        utc += 1;
    }
    utc += day - 1;
    utc *= DAY_SEC;
    temp = (hour * 60);
    temp += minute;
    temp *= 60;
    utc += temp;
    utc += second;
    return utc;
}

/**
  * @brief   设置时间
  * @details 详细说明：无
  * 
  * @param[in]  time：时间数据
  * @param[in]  type：时间数据的类型
  * 
  * @return 【SUCCEE】：成功   【ERROR】：失败（错误)
  */
ErrorStatus OSAL_TimeSet(void *time, TimeType type)
{
    uint8_t temp[6];

    if (type == T_UTC)
    {
        uint32_t timestamp;
        memcpy(&timestamp, time, 4);
        OSAL_UTC2Time(timestamp, temp);
    }
    else
    {
        memcpy(temp, time, 6);
    }
    return (Device_Write(vRTC_0, temp, 6, 0) < 0) ? ERROR : SUCCESS;
}

/**
  * @brief   读取时间
  * @details 详细说明：无
  * 
  * @param[in]  time：时间数据
  * @param[in]  type：时间数据的类型
  * 
  * @return 【SUCCEE】：成功   【ERROR】：失败（错误)
  */
ErrorStatus OSAL_TimeGet(void *time, TimeType type)
{
    uint8_t temp[6];

    if (Device_Read(vRTC_0, temp, 6, 0) < 0)
    {
        return ERROR;
    }

    if (type == T_UTC)
    {
        uint32_t timestamp = OSAL_Time2UTC(temp, 0);
        memcpy(time, &timestamp, 4);
    }
    else
    {
        memcpy(time, temp, 6);
    }
    return SUCCESS;
}
